The purpose of part two of this lab is to establish communication between your computer and the Artemis board through the Bluetooth stack. We will be using Python inside a Jupyter notebook on the computer end and the Arduino programming language on the Artemis side. We will also establish a framework for sending data via Bluetooth that will be useful in future labs.
We can get the MAC Address using the code below, the result MAC Address is shown in the serial monitor.
Send an ECHO command with a string value from the computer to the Artemis board, and receive an augmented string on the computer.
We can see from the figure below that after sending a command 'ECHO' with a text 'hello', the Arduino returned a sentence 'The Robot says -> hello' in the serial monitor.
The corresponding code is show below
case ECHO:
char char_arr[MAX_MSG_SIZE];
// Extract the next value from the command string as a character array
success = robot_cmd.get_next_value(char_arr);
if (!success){
Serial.print("Not Success!");
return;
}
tx_estring_value.clear();
tx_estring_value.append("The Robot says -> ");
tx_estring_value.append(char_arr);
tx_characteristic_string.writeValue(tx_estring_value.c_str());
Serial.print("Sent back: ");
Serial.println(tx_estring_value.c_str());
break;
Add a command GET_TIME_MILLIS which makes the robot reply write a string such as “T:123456” to the string characteristic.
We can see from the figure below that after sending a command 'GET_TIME_MILLIS', the Arduino returned a string 'T:123456' in the serial monitor.
The corresponding code is show below
case GET_TIME_MILLIS:
tx_estring_value.clear();
tx_estring_value.append("T:123456");
tx_characteristic_string.writeValue(tx_estring_value.c_str());
Serial.print("Sent back: ");
Serial.println(tx_estring_value.c_str());
break;
Setup a notification handler in Python to receive the string value (the BLEStringCharactersitic in Arduino) from the Artemis board. In the callback function, extract the time from the string.
Here below is the instruction of the function we gonna use in implementing the notification handler callback function
Let's take a look at the source code of the function start_notify() and stop_notify in the figure below:
And the function of converting bytearray to string/float/int :
combining the function above, we can wrote the code below in our Jupyter Notebook:
def handle_notification(uuid,bytearray):
converted_num = ble.bytearray_to_float(bytearray)
print('The current time is : ',converted_num)
ble.start_notify(ble.uuid['RX_FLOAT'],handle_notification)
time.sleep(3)
ble.stop_notify(ble.uuid['RX_FLOAT'])
And then get the result:
As shown above, our computer successfully handled the notification sent from the Arduino
Write a loop that gets the current time in milliseconds and sends it to your laptop to be received and processed by the notification handler. Collect these values for a few seconds and use the time stamps to determine how fast messages can be sent. What is the effective data transfer rate of this method?
Here below is the code written in the Arduino
case HOW_FAST:
cnt=0;
while(cnt < MAX_STRING)
{
tx_estring_value.clear();
tx_estring_value.append("T:");
tx_estring_value.append((float)millis());
tx_characteristic_string.writeValue(tx_estring_value.c_str());
cnt++;
}
break;
Some IMPORTANT notes:
Then we can implement the callback function in Jupyter Notebook to receive information from Arduino
To make the timestamps results shown in the figure above easier to analyze, we made line-plots below:
As shown above, the time interval in this approach is unstable, the difference is 0ms or about 60ms
By further caculating the data from the time interval, we get the result:
Now create an array that can store time stamps. This array should be defined globally so that other functions can access it if need be. In the loop, rather than send each time stamp, place each time stamp into the array. (Note: you’ll need some extra logic to determine when your array is full so you don’t “over fill” the array.) Then add a command SEND_TIME_DATA which loops the array and sends each data point as a string to your laptop to be processed. (You can store these values in a list in python to determine if all the data was sent over.)
To store the data in the array, we use the code below in the Arduino:
And the results in the Jupyter Notebook is shown below:
The line-plot based on this data is:
And the analyzed data is:
Discussion:
This approach is much more stable since the time difference is almost 0 with seldom fluctuate, and the standard deviation of the time difference is also much smaller than that of the last approach
Add a second array that is the same size as the time stamp array. Use this array to store temperature readings. Each element in both arrays should correspond, e.e., the first time stamp was recorded at the same time as the first temperature reading. Then add a command GET_TEMP_READINGS that loops through both arrays concurrently and sends each temperature reading with a time stamp. The notification handler should parse these strings and add populate the data into two lists.
Here below is the code in Arduino, which can store and send both the timestamps and temperature:
Here we used the command float temp_f = getTempDegF() to get the temperature data from Arduino
And the received result in the Jupyter Notebook is shown below:
The result shows that the time and temperature data are well received and separared in my laptop
Discuss the differences between these two methods, the advantages and disadvantages of both and the potential scenarios that you might choose one method over the other. How “quickly” can the second method record data? The Artemis board has 384 kB of RAM. Approximately how much data can you store to send without running out of memory?
Discussion:
The first method is sending information immidiately after gasping the data from the Arduino, whose data transfer time interval is relatively unstable, and this method do not require much on the RAM.
The second method is storing data in the array and then read and transfer the data from the Arduino to the computer, which is much more stable but needs more RAM space to operate.
For the second approach, if we are sampling data at 1 kHz and each sample is 4 bytes (32 bits), we would be storing data at a rate of 4 kilobytes per second (1 kHz * 4 bytes). The 384kB RAM could be filled up in 96 seconds (384 kB / 4 kB per second).
Effective Data Rate And Overhead: Send a message from the computer and receive a reply from the Artemis board. Note the respective times for each event, calculate the data rate for 5-byte replies and 120-byte replies. Do many short packets introduce a lot of overhead? Do larger replies help to reduce overhead? You may also test additional reply sizes. Please include at least one plot to support your write-up.
Here below is the code of sending messages.
Here below is the code of receiving and replying the message.
After testing, the 5-byte rate is 21.05 bytes/sec, and the 120-byte rate is 517.28 bytes/sec
The graph below illustrates a clear correlation between the data rate and the quantity of bytes transmitted. This pattern indicates that sending larger replies contributes to a reduction in overhead.
Reliability: What happens when you send data at a higher rate from the robot to the computer? Does the computer read all the data published (without missing anything) from the Artemis board? Include your answer in the write-up.
To test the Reliability in high-speed transfer, we print the result of the function SEND_TIME_DATA in both Arduino and Jupyter lab, here below is the results:
We could notice that the transfer rate is very high and the lost of data did not occur, which implys that this system has a good Reliability